package edu.nus.mtech.sem1.ca.plan;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import edu.nus.mtech.sem1.ca.exception.DuplicateException;
import edu.nus.mtech.sem1.ca.plan.valueadd.ValueAddedService;
import edu.nus.mtech.sem1.ca.utils.Logger;
import edu.nus.mtech.sem1.ca.utils.TelephonyUtils;



public class Account implements Serializable{
	
	private String accountNumber;
	private Set<Plan> plans=new HashSet<Plan>();
	
	
	

	public Map getCharge() {
	
		return null;
	}
	
	public double getTotalCharge() {
	
		return 0.0;
	}
	
	public void addPlan(Plan plan) throws DuplicateException{
		if (plan==null){
			return;
		}
		//Plan tempPlan=getPlanObjectIfExists(plan);	
			//Remember, duplicate plans will be GONE !!!
		boolean addSuccessful=this.plans.add(plan);
		Logger.log("Plan addition Successful ???"+addSuccessful);

}
	
	
	public void addValueAddedServiceToPlan(Plan plan, ValueAddedService vaService) throws DuplicateException{
		
			Plan tempPlan=getPlanObjectIfExists(plan);	
			if (tempPlan!=null){
				//Remember, duplicate vaServices will be GONE !!!
				tempPlan.addValueAddedService(vaService);
			}
			else{
				plan=new Plan();
				plan.addValueAddedService(vaService);
				plans.add(plan);
			}
	}

	/**
	 * Alright, the only purpose of this method is to overcome the lack of "get (object)" in set for obvious reasons.
	 * Few solutions were considered and it was finally decided to stick to a Set iterator
	 * 
	 * The solutions that were considered were : 
	 * 
	 * 1) We could use a Map with only keys and no values but you know that's pretty damn ugly.
	 * Leave alone the curses from whoever-sees-this-code. 
	 * 
	 * 2) Also, since the Map interface has a put(key,value), there is no way we could stick to a put(object_alone) method. 
	 * For crying out loud, where the heck is a single-dimensional map. Python is way way better with membership checks on sets.
	 * 
	 * 3) Write our own single-dimensional map without implementing the Map interface but implementing all the other methods of it (except our customized put(object_alone)). 
	 * Of course, you could copy all the implementations from HashMap's source. Jeeez.. why do i feel dirty when I say "copy"? Chuck it.  
	 * 
	 * 4) Use a SortedList for storing Plans and use Collections.binarySearch to vroooooomm to the object but List really???? 
	 *  On what sane earth would an user account have two plans of the same type and even phone number?  May be if the operator is called CheatTel or ConHub.
	 *  
	 * For the glory of God, I might as well iterate. 
	 * 
	 * 
	 * @param plan
	 * @return
	 */
	//making method as Public for testing
	public Plan getPlanObjectIfExists(Plan plan) {
		
		if (plan==null){
			return null;
		}
		Plan returnPlan=null;
		
		if (plans!=null){
			for (Plan eachPlan:plans){
				//Plan id is all that is going to matter 
				if (eachPlan.getPlanId().equals(plan.getPlanId())){
					returnPlan=eachPlan;
					break;
				}
			}
		}
		return returnPlan;
	}

	public String getAccountNumber() {
		return accountNumber;
	}

	public void setAccountNumber(String accountNumber) {
		this.accountNumber = accountNumber;
	}

	public Set<Plan> getPlans() {
		return plans;
	}

	public void setPlans(Set<Plan> plans) {
		this.plans = plans;
	}

	@Override
	public String toString() {
		return plans.toString();
	}
	
	@Override
	public boolean equals(Object accountObj) {
		boolean allResult=false;
		
		if (accountObj!=null && accountObj instanceof Account){
			Account incomingAccount=(Account)accountObj;
			
			if (incomingAccount.getAccountNumber().equals(accountNumber)){
				allResult=true;
			}
			if (incomingAccount.getPlans().equals(plans)){
				allResult=allResult && true;
			}
			
		}
		return allResult;
	}
	
	@Override
	public int hashCode() {
		return TelephonyUtils.getHashCode(accountNumber)+getPlans().hashCode();
	}
}
